package com.tqz.juc.jmm;

import lombok.extern.slf4j.Slf4j;
import sun.misc.Contended;

/**
 * <p>JMM内存模型指令重排。
 * volatile关键字禁止指令重排，从而保证多线程环境下代码的顺序执行。
 * 或者使用jdk的魔法类Unsafe类的fullFence()。
 *
 * {@link Contended} 解决伪共享，，要设置 -XX:-RestrictContended=false，
 * 它默认为 true（意味仅限 JDK 内部的类使用）。
 *
 * <p>屏障类型 指令示例 说明:
 * <ul>
 * <li>LoadLoad Load1; LoadLoad; Load2 保证load1的读取操作在load2及后续读取操作之前执行。
 * <li>StoreStore Store1; StoreStore; Store2 在store2及其后的写操作执行前，保证store1的写操作已刷新到主内存。
 * <li>LoadStore Load1; LoadStore; Store2 在stroe2及其后的写操作执行前，保证load1的读操作已读取结束。
 * <li>StoreLoad Store1; StoreLoad; Load2保证store1的写操作已刷新到主内存之后，load2及其后。
 * </ul>
 *
 * @author tianqingzhao
 * @since 2022/1/16 0:03
 */
@Slf4j
public class JavaMemoryModelOrderResetTest {
    
    private volatile static int x = 0, y = 0;
    
    private volatile static int a = 0, b = 0;
    
    public static void main(String[] args) throws InterruptedException {
        int i = 0;
        for (; ; ) {
            i++;
            x = 0;
            y = 0;
            a = 0;
            b = 0;
            Thread t1 = new Thread(new Runnable() {
                public void run() {
                    shortWait(10000);
                    a = 1;
                    x = b;
                    //                    UnsafeInstance.reflectGetUnsafe().fullFence();
                }
            });
            
            Thread t2 = new Thread(new Runnable() {
                public void run() {
                    b = 1;
                    //                    UnsafeInstance.reflectGetUnsafe().fullFence();
                    y = a;
                }
            });
            
            t1.start();
            t2.start();
            t1.join();
            t2.join();
            
            String result = "第" + i + "次 (" + x + "," + y + "）";
            if (x == 0 && y == 0) {
                System.out.println(result);
                break;
            } else {
                log.info(result);
            }
        }
        
    }
    
    /**
     * 等待一段时间，时间单位纳秒
     *
     * @param interval
     */
    public static void shortWait(long interval) {
        long start = System.nanoTime();
        long end;
        do {
            end = System.nanoTime();
        } while (start + interval >= end);
    }
    
}
